/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kurvykurvy.image;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;
import javax.imageio.ImageIO;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.tiff.TiffField;
import org.apache.sanselan.formats.tiff.constants.ExifTagConstants;
import org.openide.util.Exceptions;

/**
 *
 * @author HY
 */
public class LoadedImage
        implements Transferable
{

    public final static String MIME_TYPE = "application/kurvy-loaded-image; class=" + LoadedImage.class.getCanonicalName();
    public static DataFlavor LOADED_IMAGE_DATA_FLAVOR;
    public final static LoadedImage BLANK_IMAGE = new LoadedImage();

    static
    {
        try
        {
            LOADED_IMAGE_DATA_FLAVOR = new DataFlavor( MIME_TYPE );
        }
        catch ( ClassNotFoundException ex )
        {
            Exceptions.printStackTrace( ex );
        }
    }

    File source;
    BufferedImage sourceImage;
    BufferedImage workImage;
    Vector<AffineTransform> transformations;

    protected LoadedImage()
    {
    }

    public LoadedImage( BufferedImage img )
    {
        sourceImage = img;
    }

    public LoadedImage( File src )
            throws IOException
    {
        this.source = src;
        sourceImage = ImageCacheLoader.loadImage( src.toURI().toURL() );//ImageIO.read( this.source );
//        try
//        {
//            IImageMetadata metaData = Sanselan.getMetadata( src );
//            if ( metaData instanceof JpegImageMetadata )
//            {
//                JpegImageMetadata jpgMetaData = (JpegImageMetadata) metaData;
//                TiffField exifField = jpgMetaData.findEXIFValue( ExifTagConstants.EXIF_TAG_ORIENTATION );
//                if ( exifField != null )
//                {
//                    System.out.println( "*** EXIF Orientation : " + exifField.getValue() );
//                }
//            }
//        }
//        catch ( ImageReadException ex )
//        {
//            Exceptions.printStackTrace( ex );
//        }
    }

    private void createWorkImage()
    {
        Dimension size = new Dimension( 1024, 768 );
        if( this.sourceImage != null )
        {
            size.setSize( this.sourceImage.getWidth(), this.sourceImage.getHeight() );
        }

        BufferedImage img = new BufferedImage( size.width, size.height, BufferedImage.TYPE_INT_RGB );
        Graphics2D g2 = img.createGraphics();

        if( sourceImage != null )
        {
            g2.drawImage( sourceImage, null, 0, 0 );
        }
        g2.dispose();

        workImage = img;
    }

    public double deriveXScale()
    {
        double result = 1.0;
        if ( transformations != null )
        {
            for ( Iterator<AffineTransform> it = transformations.iterator(); it.hasNext(); )
            {
                AffineTransform transform = it.next();
                result *= transform.getScaleX();
            }
        }
        return result;
    }

    public BufferedImage applyTransform( AffineTransform transform )
    {
        if ( workImage == null )
            createWorkImage();

        System.gc();
        double scaleX = transform.getScaleX();//( transform.getScaleX() > 1 )? transform.getScaleX():1;
        double scaleY = transform.getScaleY();//( transform.getScaleY() > 1 )? transform.getScaleY():1;
        BufferedImage image = new BufferedImage( (int) (workImage.getWidth() * scaleX), (int) (workImage.getHeight() * scaleY), BufferedImage.TYPE_INT_RGB );
        Graphics2D g2 = image.createGraphics();
        AffineTransform originalTransform = g2.getTransform();

        RenderingHints hints = g2.getRenderingHints();
        hints.put( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC );
        hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );

        System.out.println( "Applied Transformation: " );
        System.out.println( "Translation : " + transform.getTranslateX() + ", " + transform.getTranslateY() );
        transform.translate( -transform.getTranslateX(), -transform.getTranslateY() );
        System.out.println( "Test : " + transform.getTranslateX() + ", " + transform.getTranslateY() );
        
        g2.setTransform( transform );
        g2.drawImage( workImage, null, 0, 0 );
        g2.setTransform( originalTransform );
        g2.dispose();

        if ( transformations == null )
            transformations = new Vector<AffineTransform>();

        transformations.add( transform );
        workImage = image;
        return workImage;
    }

    public String getFilename()
    {
        if ( this.source != null )
        {
            return this.source.getName();
        }
        else
        {
            return "Unknown";
        }
    }

    public String getFilepath()
    {
        if ( this.source != null )
        {
            return this.source.getPath();
        }
        else
        {
            return "";
        }
    }

    public BufferedImage getImage()
    {
        if ( workImage == null )
            createWorkImage();

//        javax.swing.JOptionPane.showMessageDialog( null, new javax.swing.ImageIcon( workImage ) );
        return workImage;
    }

    @Override
    public int hashCode()
    {
        if ( this.sourceImage != null )
        {
            return this.sourceImage.hashCode();
        }
        else
        {
            return super.hashCode();
        }
    }

    @Override
    public boolean equals( Object obj )
    {
        boolean result = false;
        if ( obj instanceof BufferedImage )
        {
            result = this.sourceImage.equals( obj );
        }
        else
        {
            result = super.equals( obj );
        }
        return result;
    }

    public Dimension getSize()
    {
        if ( workImage == null )
            createWorkImage();

        return new Dimension( this.workImage.getWidth(), this.workImage.getHeight() );
    }

    public BufferedImage getSourceImage()
    {
        return sourceImage;
    }
    DataFlavor supportedDataFlavor = new DataFlavor( LoadedImage.class, MIME_TYPE );

    public DataFlavor[] getTransferDataFlavors()
    {
        return new DataFlavor[]
                {
                    supportedDataFlavor
                };
    }

    public boolean isDataFlavorSupported( DataFlavor flavor )
    {
        boolean result = false;
        if ( flavor != null && MIME_TYPE.equals( flavor.getMimeType() ) )
        {
            result = true;
        }
        return result;
    }

    public Object getTransferData( DataFlavor flavor )
            throws UnsupportedFlavorException, IOException
    {
        if ( isDataFlavorSupported( flavor ) )
        {
            return this;
        }
        else
        {
            return null;
        }
    }
}
